- // ==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/jquery@3.6.0/dist/jquery.min.js
- // @require https://unpkg.com/vue@2.6.14/dist/vue.min.js
- // @require https://unpkg.com/tiny-oss@0.5.1/dist/tiny-oss.min.js
- // @require https://unpkg.com/vio-utils@2.7.8/index.js
- // @require https://unpkg.com/@vizoy/tmk-utils@1.4.1/index.js
- // @require https://unpkg.com/@vizoy/sw2@1.0.3/sw2.js
- // @require https://unpkg.com/axios@0.27.2/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()