您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
可自定义css选择器屏蔽页面广告,添加js脚本
// ==UserScript== // @name 添加自定义css和js(广告屏蔽等) // @description 可自定义css选择器屏蔽页面广告,添加js脚本 // @namespace _cus_ad_sp // @version 2.11.2 // @author vizo // @license MIT // @include /https?\:\/\/(?!greasyfork).*/ // @run-at document-start // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM_addElement // @grant GM_registerMenuCommand // @grant GM_setClipboard // @grant GM_xmlhttpRequest // @grant GM_download // @grant unsafeWindow // @connect * // @require https://unpkg.com/[email protected]/dist/jquery.min.js // @require https://unpkg.com/[email protected]/dist/vue.min.js // @require https://unpkg.com/[email protected]/dist/tiny-oss.min.js // @require https://unpkg.com/[email protected]/index.js // @require https://unpkg.com/@vizoy/[email protected]/index.js // @require https://unpkg.com/@vizoy/[email protected]/sw2.js // @require https://unpkg.com/[email protected]/dist/axios.min.js // @noframes // ==/UserScript== Object.assign(TMK, vio) TMK.sw = sw unsafeWindow.TMK = TMK unsafeWindow.$j = $ unsafeWindow.axios = axios const html = (s) => { return s[0] } const G = { hostIgnore: /\b(taobao|jd|tmall|bilibili|iviewui)\.com|^(192\.|localhost|127\.)\b|\bbaidu\.com\/s\?wd=|quicker/i, ifrIgnore: /\b(github|qq|geetest|taobao|aliyundrive|163)\.com|\brecaptcha/i, linkIgnore: /\b(github|gitee)\.com/i, tmpTime: 0, cusStyCnt: '', html: html` <div id="wp5rh" v-show="dialog1s"> <div class="mwp_5c" :class="{'expandJS': isExpandJS, 'ld': isLoad}"> <div class="tit1v">设置</div> <div class="tamp-cfg-modal" v-show="isShowTampModal"> <textarea class="txa-cfg" @change="changeTampCfg" v-model="tampCfgVal" placeholder="oss配置"></textarea> </div> <div class="c7d-item"> <p class="stiz"> <span class="s0l">打开面板快捷键</span> <span class="oss-zbtn" @click="hdlTgOssModal">oss</span> <span class="view-all-set" @click="hdlViewAllSet">{{ viewSetText }}</span> </p> <input type="text" class="inpy" v-model="eKey" placeholder="请输入a-z 用逗号隔开"> </div> <div class="c7d-item css-item-xh" v-show="!showAllSet"> <p class="stiz"> <span class="s0l">添加css(不含style标签)</span> <span class="s0r" :class="{on: disCSS}" @click="hdlTgDisCss">{{ disCssText }}</span> </p> <textarea class="txtr1z" :class="{'disabled': disCSS}" v-model="texCssVal" :readonly="disCSS" spellcheck="false" placeholder="请输入css代码" @click="hdlExpandJSJs(1)"></textarea> </div> <div class="c7d-item js-item-xh" v-show="!showAllSet"> <p class="stiz"> <span class="s0l">添加js(不含script标签)</span> <span class="s0r" :class="{on: disJS}" @click="hdlTgDisJs">{{ disJsText }}</span> </p> <textarea class="txtr1z" :class="{'disabled': disJS}" v-model="texJsVal" :readonly="disJS" spellcheck="false" placeholder="请输入js代码" @click="hdlExpandJSJs(2)"></textarea> </div> <div class="c7d-item allset-item" v-show="showAllSet"> <p class="stiz st1k"> <span class="s1p">已添加的网站(可删除) {{ addedNum }} 个 </span> <span class="s2p imt-c" @click="hdlImportCfg">导入配置</span> <span class="s2p ext-c" @click="hdlExportCfg">导出配置</span> </p> <input type="file" hidden ref="inp_hide" @change="hdlUpFile"> <textarea class="txtr1z" v-model="allAddedText"></textarea> </div> <div class="btn-w"> <button class="c5kbtn b2" @click="hdlCancel">取消</button> <button class="c5kbtn b1" @click="hdlSave">保存</button> </div> </div> </div> `, } ;(function() { if (TMK.isMobile()) return let k = GM_getValue(`_cfg_${location.host}`) || {} k = typeof k === 'string' ? JSON.parse(k) : k if (k.css && !k.disCSS) { tryAddCusSty(k.css) } })(); tryAddGmSty() function tryAddGmSty() { const isAdd = document.head.querySelector('.sty777rx') if (!isAdd) { GM_addElement('style', { class: 'sty777rx', textContent: ` html body .dn8x { display: none !important; visibility: hidden !important; overflow: hidden !important; height: 0 !important; width: 0 !important; transform: scale(0) !important; position: fixed !important; top: -99999px !important; left: -99999px !important; z-index: -100; } html body .GM-Asd-yisi, html body .GM-Asd-certain { overflow: hidden !important; background-image: none !important; } html body .adsbygoogle { display: none !important; } .GM-Asd-yisi::before, .GM-Asd-certain::before { content: attr(fxkasd); width: 100% !important; height: 100% !important; font-size: 16px; color: #ddd !important; background-color: transparent !important; display: flex !important; justify-content: center; align-items: center; font-weight: normal; font-style: normal; font-family: Arial sans-serif; position: absolute !important; top: 0; left: 0; z-index: 1; } .GM-Asd-certain.imgRx, .GM-Asd-certain.ifrIx, img.GM-Asd-certain { visibility: hidden !important; overflow: hidden !important; height: 0 !important; } .GM-Asd-certain.bdAsd::before { content: '百度广告' !important; } .GM-Asd-certain.gooAsd::before { content: '谷歌广告' !important; } .GM-Asd-certain.qrc7Box::before { content: '二维码'; } .GM-Asd-yisi > *, .GM-Asd-certain > * { visibility: hidden !important; opacity: 0 !important; } .GM-Asd-yisi:hover > *, .GM-Asd-certain:hover > * { visibility: visible !important; opacity: 0.8 !important; animation: anim5z 1.7s both; } html .rtv8x { position: relative !important; } @keyframes anim5z { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 0.8; } } @keyframes anim8z { 90% { visibility: visible; } 100% { opacity: 0; visibility: hidden; } } .GM-Asd-yisi:hover::before, .GM-Asd-certain:hover::before { animation: anim8z 1.5s both; } #wp5rh [hidden] { display: none !important; } #wp5rh, #wp5rh * { margin: 0; padding: 0; box-sizing: border-box !important; } #wp5rh { width: 28vw; height: 68vh; min-width: 440px; min-height: 400px; padding: 30px; background: #fff; border-radius: 3px; font-family: sans-serif,"HelveticaNeue",Helvetica,"PingFangSC","MicrosoftYaHei","HiraginoSansGB",Arial; line-height: 1.5; font-size: 12px; resize: both; box-shadow: 0 0 5px #ccc; position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 50050; margin: auto; } #wp5rh .mwp_5c { height: 100%; display: flex; flex-direction: column; position: relative; } #wp5rh .mwp_5c::before { content: '加载中...'; background: #fff9; font-size: 14px; color: #999; justify-content: center; align-items: center; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1; display: none; } #wp5rh .mwp_5c.ld::before { display: flex; } #wp5rh .tit1v { color: #555; font-size: 18px; text-align: center; margin-bottom: 15px; } #wp5rh .c7d-item { margin-bottom: 10px; display: flex; flex-direction: column; flex-wrap: wrap; } #wp5rh .allset-item { flex: 1; } #wp5rh .css-item-xh { flex: 3; transition: flex .3s; } #wp5rh .js-item-xh { flex: 1; transition: flex .3s; } #wp5rh .mwp_5c.expandJS .css-item-xh { flex: 1; } #wp5rh .mwp_5c.expandJS .js-item-xh { flex: 3; } #wp5rh .stiz { font-size: 14px; color: #555; margin-bottom: 3px; position: relative; text-align: left; display: flex; } #wp5rh .tamp-cfg-modal { width: 250px; height: 170px; padding: 10px; border-radius: 2px; background: #f1f1f1; position: absolute; top: -50px; right: 0; bottom: 0; left: 0; margin: auto; z-index: 2; } #wp5rh .tamp-cfg-modal .txa-cfg { width: 100%; height: 100%; resize: none; color: #777 !important; font-family: Consolas; font-size: 12px; padding: 6px; overflow-y: auto; border: 1px solid #e6e6e6; background: #fafafa; } #wp5rh .tamp-cfg-modal .txa-cfg::-webkit-input-placeholder { color: #ccc !important; } #wp5rh .stiz .s0l { flex: 1; } #wp5rh .stiz .s0r { color: #09e; cursor: pointer; user-select: none; margin-left: 10px; } #wp5rh .stiz .s0r.on { color: #9a9a9a; } #wp5rh .oss-zbtn { color: #c7c7c7; cursor: pointer; user-select: none; margin-right: 10px; } #wp5rh .view-all-set { color: #09e; cursor: pointer; user-select: none; } #wp5rh .st1k { display: flex; } #wp5rh .st1k .s1p { flex: 1; } #wp5rh .st1k .s2p { width: 65px; color: #09e; cursor: pointer; text-align: right; white-space: nowrap; overflow: hidden; } #wp5rh .inpy { flex: 0 0 auto; height: 32px; border: 1px solid #ddd; color: #555; background: #fff; border-radius: 2px; padding: 0 10px; outline: none; } #wp5rh .inpy:focus { border: 1px solid #c1c1c1; } #wp5rh .txtr1z { width: 100%; flex: 1; color: #555; padding: 6px; line-height: 1.4; overflow-x: hidden; overflow-y: auto; border-radius: 2px; border: 1px solid #ddd; background: #fff; font-size: 12px; resize: none; white-space: pre-line; outline: none; font-family: Consolas,sans-serif,"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei"; } #wp5rh .txtr1z::-webkit-input-placeholder { color: #c5c5c5; } #wp5rh .txtr1z:focus { border: 1px solid #39e; } #wp5rh .txtr1z.disabled { color: #999; background: #f5f5f5; } #wp5rh .txtr1z::-webkit-scrollbar { width: 4px; } #wp5rh .txtr1z::-webkit-scrollbar-corner, #wp5rh .txtr1z::-webkit-scrollbar-track { background-color: #fff; } #wp5rh .txtr1z::-webkit-scrollbar-thumb { background: #fff; } #wp5rh .txtr1z:hover::-webkit-scrollbar-thumb { background: #e1e1e1; } #wp5rh .txtr1z:hover::-webkit-scrollbar-corner, #wp5rh .txtr1z:hover::-webkit-scrollbar-track { background-color: #f7f7f7; } #wp5rh .btn-w { margin-top: 5px; display: flex; flex-direction: row-reverse; } #wp5rh .btn-w .c5kbtn { width: 90px; height: 32px; border-radius: 2px; margin-right: 10px; font-family: sans-serif,"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei" !important; cursor: pointer; outline: none; border: 0; } #wp5rh .btn-w .c5kbtn.b1 { color: #fff !important; background: #09e !important; } #wp5rh .btn-w .c5kbtn.b2 { color: #555 !important; background: #f1f1f1 !important; } #wp5rh .btn-w .c5kbtn:first-child { margin-right: 0; } #wp5rh .btn-w .c5kbtn:focus { border: 0; } #wp5rh .btn-w .c5kbtn:hover { opacity: 0.9; } `, }) } } const vm = new Vue({ data() { return { // 模态框状态 dialog1s: false, // 快捷键名称 eKey: '', showAllSet: false, // css代码 texCssVal: '', // js代码 texJsVal: '', // 已添加的网站 allAddedText: '', disCSS: false, disJS: false, // 是否展开js isExpandJS: false, isLoad: false, // oss配置modal isShowTampModal: false, tampCfgVal: '', } }, computed: { viewSetText() { return this.showAllSet ? '查看当前网站' : '查看全部网站' }, addedNum() { return this.allAddedText .split('\n') .filter(v => !!v) .length }, disCssText() { return this.disCSS ? '已禁用' : '禁用css' }, disJsText() { return this.disJS ? '已禁用' : '禁用js' }, }, watch: { eKey(nVal) { this.eKey = /[a-z\,]/.test(nVal) ? nVal : '' GM_setValue('_gus_keyboard', this.eKey) }, dialog1s(nVal) { if (!nVal) { this.showAllSet = false this.isShowTampModal = false } }, }, methods: { setGmVal(obj) { obj.firstTime = obj.firstTime ?? Math.trunc(Date.now() / 1e3) return GM_setValue(`_cfg_${location.host}`, obj) }, getGmVal() { let gmVal = GM_getValue(`_cfg_${location.host}`) || {} return typeof gmVal === 'string' ? JSON.parse(gmVal) : gmVal }, hdlTgOssModal() { this.isShowTampModal = !this.isShowTampModal }, hdlExpandJSJs(type) { this.isExpandJS = type === 2 }, changeTampCfg() { GM_setValue('tampOssCfg7n', this.tampCfgVal) }, async hdlSave() { if (!this.showAllSet) { this.saveCssAndJs() this.initAddedWebToTextArea() } else { this.updateTextAreaValToGm() await this.saveJsonToOss('state') await this.saveJsonToOss('cfg') location.reload() } this.dialog1s = false }, hdlCancel() { this.dialog1s = false }, // 禁用css hdlTgDisCss() { this.disCSS = !this.disCSS }, // 禁用js hdlTgDisJs() { this.disJS = !this.disJS }, async saveCssAndJs() { tryAddCusSty(this.texCssVal) document.querySelectorAll('.cusSty9z1p').forEach((v, i, y) => { if (i !== y.length - 1) { v.remove() } else { v.disabled = this.disCSS } }) const gm = this.getGmVal() this.setGmVal({ ...gm, css: this.texCssVal, js: this.texJsVal, disCSS: this.disCSS, disJS: this.disJS, }) if (!this.texCssVal && !this.texJsVal) { GM_deleteValue(`_cfg_${location.host}`) } // 同步至oss if ( !await this.saveJsonToOss('state') ) { alert('同步失败, 请导出配置后在其他网站重新导入配置就能同步了') return } await this.saveJsonToOss('cfg') if ( gm.disJS !== this.disJS || gm.js !== this.texJsVal || !this.texCssVal.trim() && !this.texJsVal.trim() ) { await TMK.timeout(500) location.reload() } }, saveJsonToOss(name) { let gmCfg = GM_getValue('tampOssCfg7n') if (!gmCfg) return Promise.resolve(true) gmCfg = typeof gmCfg === 'string' ? JSON.parse(gmCfg) : gmCfg const oss = new TinyOSS(gmCfg.ossParams) const lastTime = Date.now() const data = name === 'state' ? { lastTime } : this.getAllCfg() const blob = new Blob([JSON.stringify(data)], { type: 'text/json' }) const date = TMK.fmt(Date.now(), 'Y-M-D') GM_setValue('tampCfgUpdateTime', lastTime) return new Promise(async (resolve) => { try { if (name === 'cfg') { oss.put(`json/tamp-cfg/cus-cssjs/${date}/${name}.json`, blob) await TMK.timeout(300) } await oss.put(`json/tamp-cfg/cus-cssjs/1-cfg/${name}.json`, blob, { onprogress(e) { if (e.total > 0) { return resolve(true) } } }) } catch (err) { return resolve(false) } }) }, GM_req(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url, method: 'get', responseType: 'json', onload: function(xhr) { resolve(xhr.response) }, }) }) }, async updateCfgFromOss() { const gmCfg = this.getOssCfg() const gmLastTime = GM_getValue('tampCfgUpdateTime') if (gmCfg) { try { const url1 = `${gmCfg.state}&t=${Date.now()}` const url2 = `${gmCfg.cfg}&t=${Date.now()}` const res = await this.GM_req(url1) const { lastTime } = res const now = Date.now() if ( !gmLastTime || lastTime > gmLastTime || now - gmLastTime > 3e4 ) { const rCfg = await this.GM_req(url2) this.updateJsonToGm(rCfg) // 这里也初始化一次 this.initAddedWebToTextArea() GM_setValue('tampCfgUpdateTime', now) } } catch (e) { TMK.log( e.message ) } } }, // 判断是否从远程更新 tryUpdateCfgFromOss() { const gmTime = GM_getValue('pageRefreshTime') const now = Date.now() if (!gmTime || now - gmTime > 5000) { GM_setValue('pageRefreshTime', now) return new Promise(async (resolve) => { this.isLoad = true await this.updateCfgFromOss() this.isLoad = false resolve() }) } }, updateTextAreaValToGm() { const gmArr = GM_listValues() .filter(v => v.startsWith('_cfg_')) .map(v => v.replace(/^_cfg_/, '')) const cArr = this.allAddedText.split('\n') gmArr.forEach(v => { if (!cArr.some(c => v === c)) { GM_deleteValue(`_cfg_${v}`) } }) }, updateJsonToGm(obj) { if (!obj) return GM_listValues() .filter(v => /^_gus_|^_cfg_/.test(v)) .forEach(v => { GM_deleteValue(v) }) // 初始化firstTime for (let i in obj) { if (!obj[i].firstTime) { obj[i].firstTime = Math.trunc(Date.now() / 1e3) } } for (let k in obj) { GM_setValue(k, obj[k]) } }, tgCfgDialog() { this.dialog1s = !this.dialog1s }, hdlViewAllSet() { this.showAllSet = !this.showAllSet }, // 导入配置 hdlImportCfg() { this.$refs.inp_hide.click() }, // 导出配置 hdlExportCfg() { const obj = this.getAllCfg() TMK.downloadText(JSON.stringify(obj, null, 2), '1.json') }, // 获取oss配置 getOssCfg() { let gmCfg = GM_getValue('tampOssCfg7n') if (!gmCfg) return try { return typeof gmCfg === 'string' ? JSON.parse(gmCfg) : gmCfg } catch (err) {} }, initOssVal() { const gmCfg = this.getOssCfg() if (gmCfg) { this.tampCfgVal = JSON.stringify(gmCfg) } }, // 获取所有已配置的网站数据 getAllCfg() { const obj = GM_listValues() .filter(v => /^_gus_|^_cfg_/.test(v)) .reduce((acc, v) => { let gmVal = GM_getValue(v) gmVal = typeof gmVal === 'string' && gmVal > 1 ? JSON.parse(gmVal) : gmVal return { ...acc, [v]: gmVal } }, {}) for (let k in obj) { if (k.startsWith('_cfg_')) { if (!obj[k]?.css.trim() && !obj[k]?.js.trim()) { Reflect.deleteProperty(obj, k) } } } return obj }, hdlUpFile(e) { let file = e.target.files[0] if (file) { let reader = new FileReader() reader.readAsText(file, 'utf-8') reader.onload = async (evt) => { try { oUp = JSON.parse(evt.target.result) this.updateJsonToGm(oUp) if (!await this.saveJsonToOss('state')) { alert('上传失败, 请选择其他网站重新上传') return } await this.saveJsonToOss('cfg') this.initCssJsVal() this.initAddedWebToTextArea() this.initAddedScript() setTimeout(() => { location.reload() }, 200) } catch (e) { // 上传失败 } } } }, async resetCss() { this.texCssVal = '' this.disCSS = false this.setGmVal({ ...this.getGmVal(), css: '', disCSS: false, }) await this.saveJsonToOss('state') await this.saveJsonToOss('cfg') location.reload() }, async resetJs() { this.texJsVal = '' this.disJS = false this.setGmVal({ ...this.getGmVal(), js: '', disJS: false, }) await this.saveJsonToOss('state') await this.saveJsonToOss('cfg') location.reload() }, initEvt() { document.addEventListener('keydown', e => { const el = e.target const edt = el.getAttribute('contenteditable') const unEdt = edt !== 'true' && edt !== '' if ( !(/text|search|number|password|tel|url|email/.test(el.type)) && el.tagName !== 'TEXTAREA' && unEdt && !e.altKey && !e.ctrlKey && this.eKey.split(',').map(v => v.trim()).includes(e.key) ) { this.tgCfgDialog() } if (/esc/i.test(e.key)) { this.dialog1s = false } }) }, initEkey() { this.eKey = GM_getValue('_gus_keyboard') || '' }, initCssJsVal() { this.texCssVal = this.getGmVal().css || '' this.texJsVal = this.getGmVal().js || '' this.disCSS = !!this.getGmVal().disCSS this.disJS = !!this.getGmVal().disJS }, initAddedWebToTextArea() { const sorted = this.sortSiteList(GM_listValues()) const nArr = sorted .filter(v => v.startsWith('_cfg_')) .map(v => v.replace(/^_cfg_/, '')) this.allAddedText = nArr.join('\n') }, initAddedScript() { let js = this.getGmVal().js let isDisabled = this.getGmVal().disJS if (js && !isDisabled) { GM_addElement('script', { type: 'module', textContent: js, }) } }, // 网站列表排序, 按时间倒序排列 sortSiteList(siteList) { if (!siteList.length) return [] const nArr = siteList.map(v => { return { name: v, t: GM_getValue(v)?.firstTime, } }) .sort((a, b) => { return a.t - b.t > 0 ? -1 : 0 }) .map(v => v.name) return nArr }, }, async mounted() { this.initEvt() this.initOssVal() this.initEkey() await this.tryUpdateCfgFromOss() this.initAddedWebToTextArea() this.initCssJsVal() this.initAddedScript() }, }) function tryAddCusSty(styCnt) { const clsName = 'cusSty9z1p' if (document.querySelector('.' + clsName)) { return } if (styCnt) { G.cusStyCnt = styCnt } else { styCnt = G.cusStyCnt } GM_addElement('style', { class: clsName, textContent: styCnt }) } function tryAppendWp5() { const wp5 = document.getElementById('wp5rh') if (!wp5) { document.body.insertAdjacentHTML('beforeend', G.html) } } // MKS // ==== 规则 start gvz ======================= function isIgnHost() { return G.hostIgnore.test(location.host + location.pathname) } function isIgnLink(linkUrl) { try { const lnk = new URL(linkUrl.replace(/^\/\//, 'https://')) return G.linkIgnore.test(lnk.host + lnk.pathname) } catch { return false } } function isIgnIfr(url) { try { const ifr = new URL(url.replace(/^\/\//, 'https://')) return G.ifrIgnore.test(ifr.host + ifr.pathname) } catch { return false } } // 是否是广告商 function isAdvertiser(str) { return /\b(cpu\.baidu|pos\.baidu|google(sy|ad)|mediav)\b|adsbygoogle|adx\.php/.test(str) } function isBlank(el) { return /_blank/i.test(el.target) } function isHtmlOrBody(el) { return /^(body|html)$/i.test(el.nodeName) } function imgSrcYsAd(src) { if (!src || src.includes('data:image/')) { return false } const str = src.slice(0, 80) + src.slice(-120) return /(\b|_)(ad[sv]?|close|adve\w+)[-_]?\d*\.(png|jpg|gif|webp)/i.test(str) } function adTxt(s) { if (!s) return false return /(?<=[^个有打是癣很的多小种])广告(?=[^好太很多不有真比也是还])/.test(s.slice(0, 2000)) } function adm(s) { if (!s || !s.length) return false if (typeof s !== 'string' || s.includes('data:image/')) { return false } if (s.length > 2000) { s = s.slice(0, 800) + s.slice(-800) } return ( /(\b|_)ad[sv]?(ver)?[-_]?\d{0,10}(\b|_)|Adver|\badsense|(\b|_)ad[sv]?[_-]\w+/i.test(s) || /(\b|_)ad[A-Z][a-z]{2,6}\d{0,4}\b|[a-z]{4}Ad(\b|_)|(\b|_)sinaad|topAd/.test(s) || /[\b_]ave[-_]{1,6}/.test(s) || isAdvertiser(s) ) && !hasUUID(s) } // sgn function hasAdSign(el, rmTxt = false) { if (!el) return false const attArr = [...el.attributes].filter(v => v.nodeName !== 'style') return (adTxt(el.textContent) && !rmTxt) || hasAdTextInBeAf(el) || attArr.some(v => adm(v.nodeValue) || adTxt(v.nodeValue)) } function hasSibling(el) { return TMK.getSiblings(el).length > 1 } function isGif(str) { if (!str) return false return /(\.(gif|php|jsp|asp)(\b|_))|^data:image\/gif;/i.test(str) } function ysGifAd(el) { const lazy = attr(el, 'data-src') const src = attr(el, 'src') return isGif(src) && !lazy && !isSwiper(el.parentElement) && likeAdSize(el) && !isSmallSize(el) } function ysVideoAd(el) { if (el.tagName !== 'VIDEO') { return } const loop = attr(el, 'loop') const autoplay = attr(el, 'autoplay') const muted = attr(el, 'muted') return hasAdSign(el) || (loop && autoplay && muted && likeAdSize(el)) } function lnkEqImgUrl(link, imgUrl) { return link === imgUrl } function isAbs(url) { return /^https?|^\/\//i.test(url) } function isSwiper(el) { const pEl = el.parentElement const gEl = pEl.parentElement const inc = (ex) => { const p = attr(ex, 'class') return p ? p.includes('swiper') : false } return inc(el) || inc(pEl) || inc(gEl) } // 大小是否符合广告的尺寸(面积) function likeAdSize(el) { return ( !isSmallSize(el) && !isLargerSize(el) && bcr(el).height < 710 ) } function isLargerSize(el) { return bcr(el).width * bcr(el).height >= 900 * 600 && !biggerRatio(el) } function isSmallSize(el) { const w = bcr(el).width const h = bcr(el).height return ( (w * h) <= (80 * 40) || w < 65 || h < 30 ) && w > 0 && h > 0 } function siblingHasAd(el) { const sib = TMK.getSiblings(el).filter(v => !/style|script/i.test(v.nodeName)) return sib.some(v => hasAdSign(v)) } // 判断是否在页面边角吗角落 function isCorner(el) { const winW = window.innerWidth const winH = window.innerHeight const x = bcr(el).x const y = bcr(el).y const w = bcr(el).width const h = bcr(el).height const p = 40 return ( (x - p <= 0 && y - p <= 0) || (x - p <= 0 && y + h + p >= winH) || (x + w + p >= winW && y - p <= 0) || (x + w + p >= winW && y + h + p >= winH) ) && (w > 0 && w < 580) && (h > 0 && h < 620) && isFixed(el) } // 靠近顶部 function isNearTop(el) { const y = bcr(el).top const ht = bcr(document.documentElement).top return y >= 0 && y <= 60 && ht > -10 && bcr(el).width > 30 && bcr(el).height > 30 } function likeLogo(el) { return isNearTop(el) && bcr(el).left < 800 && bcr(el).width < 330 } function hasUUID(str) { return /[a-f\d]{4}(?:[a-f\d]{4}-){4}[a-f\d]{12}/i.test(str) } function hasScript(el) { return el.querySelectorAll('script').length > 0 } function hasIframe(el) { return el.querySelectorAll('iframe').length > 0 } function hasAdTextInBeAf(el) { const bf = (str) => { const cnt = getComputedStyle(el, str).getPropertyValue('content') return adTxt(cnt) } return bf('::before')|| bf('::after') } function likeQrcSize(el) { const iw = bcr(el).width const ih = bcr(el).height return iw > 80 && ih > 80 && iw < 385 && ih < 390 && iw / ih > 0.7 && iw / ih < 1.1 } function isFixed(el) { return getComputedStyle(el).position === 'fixed' } function isFxk(el) { const arr = TMK.pEls(el) return !!attr(el, 'fxkasd') || arr.some(v => !!attr(v, 'fxkasd')) } // 宽高比例疑似 function ysAdRatio(el) { const w = bcr(el).width const h = bcr(el).height return ( (w / h) > 3.6 || (h / w) > 3.6 ) && w > 30 && h > 30 } function biggerRatio(el) { const w = bcr(el).width const h = bcr(el).height return (w / h) > 10 && w > 30 && h > 30 } function ifrHasIfr(el) { try { const doc = el.contentWindow?.document return [...doc.querySelectorAll('iframe')].length > 0 } catch { return false } } // MKS // ===== 规则 end ========================================= function bcr(el) { return el.getBoundingClientRect() } function setFxK(el, str) { el.setAttribute('fxkasd', str.toUpperCase()) } function attr(el, p) { return el ? el.getAttribute(p) : '' } // 内联a标签转换为inline-block function setInlineBlock(link) { if (getComputedStyle(link).display === 'inline') { link.style.display = 'inline-block' } } // 如果是static则设置为relative function setEleAsRelative(el) { if (getComputedStyle(el).position === 'static') { el.style.position = 'relative' el.classList.add('rtv8x') } } function linkHost(url) { return TMK.isAbsUrl(url) ? new URL(url).host : null } function compareTwoBox(el1, el2) { const w = bcr(el1).width const h = bcr(el1).height const pw = bcr(el2).width const ph = bcr(el2).height const cs = getComputedStyle const pTop = Number(cs(el1).paddingTop.slice(0, -2)) const pRight = Number(cs(el1).paddingRight.slice(0, -2)) const pBom = Number(cs(el1).paddingBottom.slice(0, -2)) const pLeft = Number(cs(el1).paddingLeft.slice(0, -2)) return (Math.abs(pw + pLeft + pRight - w) < 32 && Math.abs(ph + pTop + pBom - h) < 32 && pw > 36 && ph > 36) || (w < 6 || h < 6) } function setCertainCls(el, cls = '') { const hasFk = (fk) => { return !!el?.src?.includes(fk) || [...el.querySelectorAll('iframe')]?.some(ifr => ifr?.src?.includes(fk)) } const bdCls = hasFk('pos.baidu') ? 'bdAsd' : '' const ggCls = hasFk('googlead') ? 'gooAsd' : '' const clsStr = `GM-Asd-certain ${bdCls} ${ggCls} ${cls}`.trim().replace(/\s{2,}/, ' ').split(' ') el.classList.add(...clsStr) } // 删除添加的屏蔽class和标记 function removeAsdMk(el, isRecursive) { let dArr = [el] if (isRecursive) { dArr = [...dArr, ...TMK.pEls(el)] } dArr.forEach(v => { v.classList.remove( 'GM-Asd-yisi', 'GM-Asd-certain', 'bdAsd', 'gooAsd', 'qrc7Box', 'x8x', ) v.removeAttribute('fxkasd') }) } function tryBkSiblingAndReturnRes(el) { const sib = TMK.getSiblings(el).filter(v => !/style|script/i.test(v.nodeName)) let isSuc = false sib.forEach(v => { if (hasAdSign(v)) { isSuc = true trySetMkRecursive(v, 'sib01', 'sib02') } }) return isSuc } function imgIsLargeSize(img) { if (img.nodeName !== 'IMG') { return false } return isLargerSize(img) } function trySetMkRecursive(el, mk1, mk2, clsStr = '') { if ( !el || isFxk(el) || el.id === 'wp5rh' ) { return } const isForce = clsStr.includes('dn8x') el.classList.add('x8x') setEleAsRelative(el) const zArr = [...[el], ...TMK.pEls(el)].reverse() const laEl = zArr[zArr.length - 1] let isAdd = false for (let pl of zArr) { // 避免Dom嵌套过深 if (zArr.length > 20) { break } if (compareTwoBox(pl, laEl) && pl !== el) { if ( !isHtmlOrBody(pl) && (likeAdSize(laEl) || isForce) ) { setEleAsRelative(pl) setCertainCls(pl, clsStr) setFxK(pl, mk1) isAdd = true } break } } const ipl = el.parentElement if (!likeAdSize(el) && !isForce) { return } if ( !isAdd && !isHtmlOrBody(el) ) { setCertainCls(el, clsStr) setFxK(el, mk2) } else if ( !isHtmlOrBody(ipl) && ( !isAdd || imgIsLargeSize(el) ) ) { setEleAsRelative(ipl) setCertainCls(ipl, clsStr + ' imgRx') setFxK(ipl, mk2) } } // 屏蔽body直接子元素疑似AD bda function blockBodyCdYsAd() { document.querySelectorAll('body > *, body > * > *, div[class*="fixed"], div[id*="fixed"]').forEach(el => { const isLnk = el.tagName === 'A' const largesAd = isLnk && isLargerSize(el) && document.querySelectorAll('*').length > 800 const largerZdx = Number(getComputedStyle(el).zIndex) > 9980 const imgInLnk = el.querySelectorAll('a > img').length > 0 const hasVdo = el.querySelectorAll('video').length > 0 if ( largesAd || ( ( largerZdx || hasScript(el) || imgInLnk || hasVdo ) && isCorner(el) && likeAdSize(el) ) ) { el.classList.add('dn8x') el.style.display = 'none' return } }) } // 屏蔽div中含有script的疑似AD spt function blockScriptInDiv() { document.querySelectorAll('body script').forEach(el => { const pEl = el.parentElement if (isLargerSize(pEl)) { removeAsdMk(el, true) return } if (isFxk(pEl)) { return } let prevNum = 0 let prevEl = el.previousElementSibling while (prevEl) { if (prevEl.nodeName === 'SCRIPT') { prevNum++ } prevEl = prevEl.previousElementSibling } if (!prevNum && tryBkSiblingAndReturnRes(el)) { return } if (hasAdSign(el) || hasAdSign(pEl)) { trySetMkRecursive(pEl, 's01', 's02') } }) } // 屏蔽疑似ad的box sltad function blockYsSlt() { const sArr = ['div[class*="-ad" i]', 'div[class*="ad-" i]', 'div[class*="_ad" i]', 'div[class*="ad_" i]', 'div[id*="-ad" i]', 'div[id*="ad-" i]', 'div[id*="_ad" i]', 'div[id*="ad_" i]', 'li[class*="-ad" i]', 'li[class*="ad-" i]', 'li[class*="_ad" i]', 'li[class*="ad_" i]', 'li[id*="-ad" i]', 'li[id*="ad-" i]', 'li[id*="_ad" i]', 'li[id*="ad_" i]', 'li[class*="mediav" i]', 'div[class*="mediav" i]', '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]', ] document.querySelectorAll(sArr.join(',')).forEach(el => { if (isLargerSize(el)) { removeAsdMk(el, true) return } if (isFxk(el)) { return } if (adm(el.id) || adm(el.className)) { if ( hasAdSign(el) && (likeAdSize(el) || isFixed(el)) ) { trySetMkRecursive(el, 's51', 's52') } } }) } // 屏蔽注释中包含广告的下一元素 cmt function blockCommentsHasAd() { let dgLmt = 12 const cdArr = [] let cdNds = Array.from(document.body?.childNodes || []) while (--dgLmt && cdNds.length) { cdArr.push(...cdNds) cdNds = cdNds.map(v => [...v.childNodes]).flat(1) } const cmtArr = cdArr.filter(v => { return v.nodeType === 8 && v.nodeValue.length < 50 && /廣告|广告|\bAD\b|\badsense|\badv/.test(v.nodeValue) && !/结束|end/i.test(v.nodeValue) }) cmtArr.forEach(v => { let nextEl = v.nextElementSibling while (nextEl && /style|script/i.test(nextEl.nodeName)) { nextEl = nextEl.nextElementSibling } trySetMkRecursive(nextEl, 'C01', 'C02') }) } // 屏蔽iframe广告 ifs function blockIfrAd() { document.querySelectorAll('iframe').forEach(v => { const src = attr(v, 'src') if (isIgnIfr(src)) { return } if (isLargerSize(v)) { removeAsdMk(v, true) return } if (isAdvertiser(src)) { trySetMkRecursive(v, 'f01', 'f02', 'ifrIx dn8x') return } const pEl = v.parentElement const rLen = () => { return [ hasAdSign(v), hasAdSign(pEl), ysAdRatio(v), ].filter(v => !!v).length } if ( rLen() >= 1 || ( ifrHasIfr(v) && ysAdRatio(v) ) || ( isNearTop(v) && ysAdRatio(v) ) ) { trySetMkRecursive(v, 'f01', 'f02', 'ifrIx') } }) } function blockYsVideoAd() { document.querySelectorAll('video').forEach(vdo => { const rLen = () => { return [ ysVideoAd(vdo), ] .filter(v => !!v) .length } if ( rLen() >= 1 || ysAdRatio(vdo) ) { trySetMkRecursive(vdo, 'vdo01', 'vdo02', 'vdoRb') } }) } // ims function blockYsImgInLink() { Array.from(document.querySelectorAll('a > img, a > * > img, a > * > * > img')).forEach(el => { const link = el.closest('a') const pEl = link.parentElement const lnkUrl = attr(link, 'href') if (isIgnLink(lnkUrl)) { return } const rArrLen = () => { return [ isBlank(link), ysGifAd(el), imgSrcYsAd(attr(el, 'src')), hasAdSign(link), hasAdSign(pEl), hasAdSign(el), siblingHasAd(link), siblingHasAd(el), isNearTop(el), biggerRatio(el), ].filter(v => !!v).length } if ( ( rArrLen() >= 2 && !isSmallSize(el) && !likeLogo(el) ) || ( isCorner(el) && ysGifAd(el) ) ) { trySetMkRecursive(el, 'i01', 'i02') } }) } function wchDom() { TMK.watchDom('body', TMK.throttle(() => { tryAddCusSty() tryAddGmSty() }, 500)) } function regMainEvt() { ['mousemove', 'scroll'].forEach(evt => { document.addEventListener(evt, insMainAdFn) }) } function insMainAdFn() { const pnow = performance.now() let now = Date.now() if (now - G.tmpTime > 800 || pnow < 6000) { G.tmpTime = now if (!isIgnHost()) { // 链接下的图片 blockYsImgInLink() blockBodyCdYsAd() blockYsSlt() blockCommentsHasAd() // 确认iframe广告 blockIfrAd() blockScriptInDiv() // 视频广告 blockYsVideoAd() } } } function initTimer() { insMainAdFn() setTimeout(initTimer, performance.now() < 6000 ? 350 : 8000) } async function initFunc() { if (TMK.isMobile()) return setTimeout(() => { if (!isIgnHost()) { regMainEvt() } }, 5e3) initTimer() await TMK.loadEl('body') tryAppendWp5() vm.$mount('#wp5rh') GM_registerMenuCommand('打开设置面板', vm.tgCfgDialog) GM_registerMenuCommand('清空当前网站添加的CSS', vm.resetCss) GM_registerMenuCommand('清空当前网站添加的JS', vm.resetJs) wchDom() } initFunc()