// ==UserScript== // @name BeautyToMac // @namespace http://tampermonkey.net/ // @version 0.1.2 // @icon https://www.baidu.com/favicon.ico // @description 给你一个类似Mac/Gnome的浏览体验 // @author CloundMark // @match *://www.baidu.com/* // @match *://baidu.com/* // @match *://www.so.com/* // @match *://so.com/* // @license GPLv3 // @run-at document-start // @grant none // @downloadURL none // ==/UserScript== (function () { /* 全局配置项 start*/ // 网站开关 true启用,false关闭; let baidu=true; let sou360=true; let userGlobalConfigs={ // 0、全局背景; // used is true will be get picture, false not! // bg代表背景图像,你可以从网络上引用自己喜欢的,used 为true表示启用当前分类或具体的图像,false弃用; // 内部的name建议您始终加上(但也不是必须),主要是便于哪天不需要的时候可以快速定位; // 请仿照示例添加背景 bg:{ used:true, sources:{ 'cartoon':{ used:true, sources:[ {used:true,name:'可爱猫',url:'https://i0.hdslb.com/bfs/article/dec6e7a1969748f2b4462c688367d772798d4134.png@942w_668h_progressive.png'}, {used:true,name:'粉红猫',url:'https://i0.hdslb.com/bfs/article/f45de07102e3fe83331d68dd455336ab0b2a08b3.png@942w_566h_progressive.png'}, {used:true,name:'两仪式',url:'https://i0.hdslb.com/bfs/article/c7cb8fecdd0cd7d34e89319c4b9eeb4ab543cfd0.jpg@1320w_740h.jpg'}, {used:true,name:'远坂凛',url:'https://img9.51tietu.net/pic/2019-091402/jr354qpj03ujr354qpj03u.jpg'}, {used:true,name:'红猫',url:'https://hbimg.huaban.com/011e9ec28bb2ef90550a090d2121296ee2cfe88233f56-lV1t8X_fw658'}, {used:true,name:'蓝狗',url:'https://i0.hdslb.com/bfs/article/78c032adb6df5717fc4ae465982a9d2096984223.jpg@942w_531h_progressive.jpg'}, {used:true,name:'两仪式2',url:'https://img2.baidu.com/it/u=4177750439,794883634&fm=253&fmt=auto&app=138&f=JPEG?w=935&h=500'}, {used:true,name:'saber',url:'https://i0.hdslb.com/bfs/article/49c217c9ec1e9cd707a228a509df0e7d57e0dd6e.jpg@1320w_740h.jpg'}, {used:true,name:'雅尔贝德',url:'https://i0.hdslb.com/bfs/article/38f4427201389a1fe54c12d9a62ca57681e06b3a.jpg@1320w_740h.webp'}, {used:true,name:'saber2',url:'https://i0.hdslb.com/bfs/article/0fa36a51ebd26d1d2a5621385910d9b35cdc681a.jpg@942w_590h_progressive.jpg'}, {used:true,name:'雅尔贝德2',url:'https://i0.hdslb.com/bfs/article/e7cfb2d9768b707f16685a83d7126db4787042b2.jpg@942w_668h_progressive.webp'}, {used:true,name:'白猫',url:'https://i0.hdslb.com/bfs/article/64f062d70fdba96b39dd346ab9d33dc5bf77c17f.jpg@942w_498h_progressive.webp'}, {used:true,name:'贞子',url:'https://i0.hdslb.com/bfs/article/87f6a5c7b25307c4cc7bd86acca8ed51dec25dcc.jpg@942w_666h_progressive.webp'}, {used:true,name:'大鱼',url:'https://i0.hdslb.com/bfs/article/73b003ea1c04fb3d1ed736773b3f752a8f3acfc5.jpg@942w_596h_progressive.webp'}, {used:true,name:'空蓝',url:'https://i0.hdslb.com/bfs/article/86bed00f68bbff662e202aa91215336bb3dd251e.jpg@942w_587h_progressive.webp'}, {used:true,name:'樱',url:'https://i0.hdslb.com/bfs/article/fa372e5e0a70b630b5b7eb9b4a0d1125a83535ce.png'}, {used:true,name:'薇尔莉特',url:'https://i0.hdslb.com/bfs/article/59af6572e5ea374e434a0d0cbb78c5a83e159939.jpg@942w_531h_progressive.webp'}, {used:true,name:'紫',url:'https://img1.baidu.com/it/u=2725650397,3822860203&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800'}, {used:true,name:'伊莉雅',url:'https://i0.hdslb.com/bfs/article/59b79113f3a8be33ae75009c862a4bb47fc6d87a.jpg@942w_531h_progressive.webp'}, {used:true,name:'薇尔莉特2',url:'https://i0.hdslb.com/bfs/article/0a5f6397857f8f840e9c4bb6a7b52b9623aefcd7.jpg@942w_590h_progressive.webp'}, {used:true,name:'薇尔莉特3',url:'https://i0.hdslb.com/bfs/article/ec68b813ca3a56a1e23190f9e8a255feb1d2d5e7.jpg@1320w_740h.webp'}, {used:true,name:'蒂法',url:'https://i0.hdslb.com/bfs/article/watermark/dce44704fb2b9853a970e0f2745ea15d64ac8716.jpg'}, {used:true,name:'薇尔莉特3',url:'https://i0.hdslb.com/bfs/article/7085568797e6a1923056990f71888fe9706d644b.jpg@1320w_740h.webp'}, {used:true,name:'伊莉雅2',url:'https://img0.baidu.com/it/u=3169921451,1554186398&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800'}, {used:true,name:'希丝缇娜',url:'https://i0.hdslb.com/bfs/article/65da66f0bd9e888ad572c9ab9100e4b741f2019d.jpg@942w_530h_progressive.webp'}, // 引自B站 https://www.bilibili.com/read/cv6710298?from=search {used:true,name:'深',url:'https://i0.hdslb.com/bfs/article/5c40299551a8dc24fe8c55016283206b370132aa.jpg@942w_545h_progressive.webp'}, // 引自B站 https://www.bilibili.com/read/cv17176820?from=search 原画师:杉87 {used:true,name:'晚霞',url:'https://i0.hdslb.com/bfs/article/61e693800a1f2dbab634bbb30524b151523d09fa.jpg@942w_531h_progressive.webp'}, // 引自B站 https://www.bilibili.com/read/cv17176820?from=search 原画师:Teardrops {used:true,name:'望',url:'https://i0.hdslb.com/bfs/article/7ff810942db808887d96ee65cb0f469bb68eb9aa.jpg@942w_531h_progressive.webp'}, // 原画师 ohara_tometa(小原トメ太) {used:true,name:'Bunnies',url:'https://iknow-pic.cdn.bcebos.com/c2fdfc039245d6888182ff59a5c27d1ed31b244e'}, {used:true,name:'',url:''}, {used:true,name:'',url:''}, ] }, 'natures':{ used:false, sources:[ {used:true,name:'',url:''}, {used:true,name:'',url:''}, {used:true,name:'',url:''}, ] }, } }, // 1、背景切换方式 bgSwitchMode:'multi',// 可选枚举值:['once','multi']; duration:8,// 设置背景切换的最短时间间隔,单位s;小于1s将设为1s; // 2、启用低速网络模式,非false以开启;建议始终选择low;一下网速依次越差; netThrottlMode:false,//可选枚举值:[false,'low','middle','heigh','infinity']; }; /* 全局配置项 end*/ /* 基类 */ class Base { constructor() { this.priority = 'Base'; } setBFInterval(fn,interval,...rest){ let id = setInterval((...rest) => { fn.call(this,...rest); }, interval,...rest); fn.call(this,...rest); return id; } findElement(selector,timoout=5,fq=false,intvl=100,signal=null){ if(!(selector && typeof selector === 'string')) throw TypeError('selector must be non-zero string.') return new Promise((success,reject)=>{ let timer4min, timer4big, mt; // 启用用户中断 if(signal && Object.prototype.toString.call(signal).slice(8,-1)==='AbortSignal'){ signal.addEventListenner('abort',()=>{ console.warn('异步查询,用户中断查找:',selector); reject(signal.reason); clearInterval(timer4min); clearTimeout(timer4big); mt.disconnect(); }); } // 开启快查询 if(fq){ timer4min = this.setBFInterval(()=>{ let result = document.querySelectorAll(selector); if(result.length){ success(result); clearInterval(timer4min); clearTimeout(timer4big); mt.disconnect(); } },intvl); } //开启超时策略 timer4big = setTimeout(()=>{ reject(`TimeOut[${selector}]`); clearInterval(timer4min); mt.disconnect(); },timoout*1000); //开启DOM监测 mt = new MutationObserver((_,obs)=>{ let result = document.querySelectorAll(selector); if(result.length){ success(result); clearInterval(timer4min); clearTimeout(timer4big); obs.disconnect(); } }); mt.observe(document.documentElement,{childList:true,subtree:true}); }); } run() { throw TypeError('ChildrenClass must have this method!'); } } class NoAdBase extends Base { constructor(selector){ super(); this.selector = selector; this.allElements = []; } } /* 反广告 */ class AntiAdSoft extends NoAdBase { constructor(selector) { super(selector); this.allElements = [...document.querySelectorAll(this.selector)]; Reflect.defineProperty(this, 'priority', { value: 'NoAdSoft', configurable: false, enumerable: true, writable: false }); } run() { for (let i = 0; i < this.allElements.length; i++) { this.allElements[i].style.cssText += 'display:none !important'; } } } class AntiAdHard extends NoAdBase { constructor(selector){ super(selector); this.allElements = null; Reflect.defineProperty(this, 'priority', { value: 'NoAdHard', configurable: false, enumerable: true, writable: false }); } run(){ this.findElement(this.selector).then(results=>{ this.allElements = [...results]; if(this.allElements.length){ this.allElements.forEach(item=>item.remove()); } }).catch(info=>{ console.warn(`AntiHard No ${info}.`); }) } } class AntiAdDynamic extends NoAdBase{ constructor(adDynamic){ super(); //dynamicRules if(!this.constructor.UNIQUEINSTANCE){ this.dynamicRules = adDynamic; this.maid = []; Reflect.defineProperty(this, 'priority', { value: 'NoAdDynamic', configurable: false, enumerable: true, writable: false }); Reflect.defineProperty(this.constructor, 'UNIQUEINSTANCE', { value: this, configurable: false, enumerable: false, writable: false }); }else{ return this.constructor.UNIQUEINSTANCE; } } run(){ for(let item of this.dynamicRules){ let mt = new MutationObserver(()=>{ let tmpNodeList=document.querySelectorAll(item.ref); if(tmpNodeList.length){ let resultWrapper=item.fire(tmpNodeList); resultWrapper.forEach(o=>o.remove()); } }) this.maid.push(mt); let eye = document.querySelector(item.eyeSlector); if(eye){ mt.observe(eye,item.options); }else{ this.findElement(item.eyeSlector) .then(eles=>mt.observe(eles[0],item.options)) .catch(info=>console.warn(`${info}---无广告参照点:${item.ref} from ${item.eyeSlector}.`)); } } } } /* 处理样式的基类 */ class ModifyStyleBase extends Base { constructor(selector) { super(selector); } getNewElement(tag,options={}){ let tmp = document.createElement(tag); Object.assign(tmp,options); return tmp; } setStyle() { throw TypeError('ChildrenClass must have this method!'); } removeStyle() { throw TypeError('ChildrenClass must have this method!'); } getStyle() { throw TypeError('ChildrenClass must have this method!'); } observeStyle() { throw TypeError('ChildrenClass must have this method!'); } stringToMap(styleText) { // 将 “div{height:20px;width:30px;content:':;'}span a{color:'red';text-align:center;}” 转换成 // Map对象 {'selector':{'attr1':'value1','attr2':'value2'}} // 原因是用户输入可能不规范,转成统一格式便于处理 // 输入content属性不能包含 {}:; let result = new Map(); if(!styleText) return result; let pattern4InnerText = /[a-z0-9+~|*$()[\]. \n\t\f\r\v#:=>,_"'-^]+{[^}]*?}/gi; let pattern4PerRule = /([a-z0-9+~|*$()[\]. \n\t\f\r\v#:=>,_"'-^]+){([^}]*?)}/i; let cssRulesText = [...styleText.matchAll(pattern4InnerText)].flat(); for(let rule of cssRulesText){ let [selector,values] = rule.match(pattern4PerRule).slice(1); if(!selector || !values) throw Error(selector+'someThing is Wrong'); selector = selector.trim(); values = values.split(';').filter(o=>o.trim()); let style = result.get(selector); if(!style) { style = new Map(); result.set(selector,style); } for(let attr of values){ let idx=attr.indexOf(":"); let k = attr.slice(0,idx).trim(); let v = attr.slice(idx+1).trim(); if (!k) throw Error(selector+' attr is Wrong'); if(v == '') continue; style.set(k,v); } } return result; } mapToString(map) { if(Object.prototype.toString.call(map).slice(8,-1) !== 'Map') throw TypeError('map Must be Map'); let result = ''; for(let [selector, valMaps] of map){ result = result + selector + '{'; for(let [k,v] of valMaps){ result = result + k + ":" + v + ";"; } result += "}"; } return result } string2DToMap(styleText){ let result = new Map(); if(!styleText) return result; for(let item of styleText.split(';').filter(i=>i.trim())){ let key = item.slice(0,item.indexOf(':')); let val = item.slice(item.indexOf(':')+1); result.set(key.trim(),val.trim()); } return result; } getAllAvailableBg(){ //与项目的配置项耦合在一起了 let tempImgLists = []; if(this.configs.bg.used){ let bg = this.configs.bg.sources; for(let modules of Object.values(bg)){ if(modules.used){ for(let item of modules.sources){ if(item.used && item.url && (/^https?:/i).test(item.url)){ tempImgLists.push(item); } } } } } return tempImgLists; } getSingleBg(availableList){ // 为空的时候会返回undefined if(window.crypto&&window.crypto.getRandomValues){ return availableList[Math.floor(crypto.getRandomValues((new Uint32Array(1)))[0]/0xFFFFFFFF*availableList.length)]; }else{ return availableList[Math.floor(Math.random()*availableList.length)]; } } wrapperEvent(customEvent,callback){ // 用于自定义包装事件 if(typeof customEvent !== 'string') throw TypeError('EventName must be string.'); if(typeof callback !== 'function') throw TypeError('callback must be function.'); let customElement = new Event(customEvent,{cancelable:false,bubbles:true}); return function(){ customElement.content = arguments; let result=callback.apply(this,[...arguments]); window.dispatchEvent(customElement); return result; } } } /* 定义样式在标签内处理的类 */ /* 此处的设置不会被网站设置覆盖的样式,为弱类型设置;全局唯一实例的style标签 */ class ModifyStyleFromTag extends ModifyStyleBase { constructor() { super(); if(!this.constructor.UNIQUEINSTANCE){ this.observers = []; this.styleEle = this.getNewElement('style'); this.styleEle.id = this.styleEle.id || Math.random().toString(36).slice(2); Reflect.defineProperty(this, 'priority', { value: 'Tag', configurable: false, enumerable: true, writable: false }); Reflect.defineProperty(this.constructor, 'UNIQUEINSTANCE', { value: this, configurable: false, enumerable: false, writable: false }); }else{ return this.constructor.UNIQUEINSTANCE; } } setStyle(css) { // css 可以是样式对象或者是css文本;filter指定给满足条件的元素添加样式,可以是NodeList或[[HTMLElement]],或者回调函数; // let cssTest = "div {width:30px ;height: 40px;}span a ,b> strong {color:'red';line-height:1rem}"; let newStyleMap = this.stringToMap(css); let currentMap = this.stringToMap(this.styleEle.innerText); for(let [selector, values] of newStyleMap){ let currentStyleMap = currentMap.get(selector); if(!currentStyleMap){ // 空说明是新选择器; currentMap.set(selector,values); }else{ // 说明是旧选择器; for(let [k,v] of values){ currentStyleMap.set(k,v); } } } this.styleEle.innerText = this.mapToString(currentMap); } getStyle(selector,styleKey) { // 返回一个样式字符串值 selector = selector.trim(); return this.stringToMap(this.styleEle.innerText).get(selector).get(styleKey); } getAllStyle() { // 返回的是map对象; return this.stringToMap(document.getElementById(this.styleEle.id).innerText); } removeStyle(selector,styleKeys=[]) { // styleKey应该是数组;eg,['width','height',...]; selector = selector.trim(); let currentMap = this.stringToMap(this.styleEle.innerText); let flag = true; if (!styleKeys.length) { // 1 如果styleKey为空的话,则删除整个选择器 flag = currentMap.delete(selector); }else{ // 2 非空的话则要每个处理 let currentStyleMap = currentMap.get(selector); if(!currentStyleMap) return false; for(let k of styleKeys){ k = k.trim(); if(!currentStyleMap.delete(k)) console.warn(`${selector}->${k} dont exist`); } if(!currentStyleMap.size) currentMap.delete(selector); } this.styleEle.innerText = this.mapToString(currentMap); return flag; } observeStyle() { // 监测要监视的style标签内容 this.observers[0] = new MutationObserver(()=>{ if(!this.styleEle.isConnected){ this.connect(); console.warn('style tag is missing, Re-Connected '+this.styleEle.id); } }); // this.observer.observe(document.head,{childList:true,subtree:true,characterData:true,attributeFilter:['class','style','id']}); if(document.head){ this.observers[0].observe(document.head,{childList:true}); }else{ this.findElement('head').then(rsp=>this.observers[0].observe(rsp[0],{childList:true})); } } connect() { if(!this.styleEle) throw Error('无样式对象'); if(!document.head){ this.findElement('head') .then(head=>head[0].appendChild(this.styleEle)) .catch((e)=>{ console.warn('Tag cant insert to document.head immediately, info: ',e); let timer=this.setBFInterval(()=>{ let result=document.querySelectorAll('head'); if(result.length){ result[0].appendChild(this.styleEle); clearInterval(timer); console.log('Tag low performace insert head!') clearTimeout(t4o); } },100); let t4o=setTimeout(()=>{ clearInterval(timer); console.error('head cant be found.'); },60*1000); }); }else{ document.head.appendChild(this.styleEle); } } run(){ this.connect(); this.observeStyle(); } } /* 定义样式在行内处理的类 */ /* 此处的样式设置可能会被网站设置覆盖的样式,为强类型设置 */ class ModifyStyleFromLine extends ModifyStyleBase { constructor() { super(); if(!this.constructor.UNIQUEINSTANCE){ this.observers = null; // 这是一个补救,用于针对固有样式进行保留(选择器:函数对象); this.fixedStyleObj=null; this.configs = null; this.variableSelector = {}; // 此属性处理每次必须变更的对象;[] Reflect.defineProperty(this, 'priority', { value: 'Line', configurable: false, enumerable: true, writable: false }); Reflect.defineProperty(this, 'styleMaps', { value: new Map(), configurable: false, enumerable: true, writable: false }); Reflect.defineProperty(this.constructor, 'UNIQUEINSTANCE', { value: this, configurable: false, enumerable: false, writable: false }); }else{ return this.constructor.UNIQUEINSTANCE; } } getAllStyle() { return this.styleMaps; } getStyle(selector,styleKey) { // 返回一个样式字符串值 return this.styleMaps.get(selector.trim()).get(styleKey.trim()); } setStyle(css) { // css 可以是样式对象或者是css文本;filter指定给满足条件的元素添加样式,可以是NodeList或[[HTMLElement]],或者回调函数; // 需要覆盖固有样式中希望被覆盖掉的; // let cssTest = "div {width:30px ;height: 40px;}span a ,b> strong {color:'red';line-height:1rem}"; let newStyleMap = this.stringToMap(css); let currentMap = this.styleMaps; for(let [selector,values] of newStyleMap){ let currentStyleMap = currentMap.get(selector); if(!currentStyleMap){ currentMap.set(selector,values); }else{ for(let [k,v] of values){ currentStyleMap.set(k,v); } } } } updateGlobalStyle(){ for(let [selector,styleItems] of this.styleMaps){ let nodeList = document.querySelectorAll(selector); //console.log(selector,'设置样式===>',nodeList); let cssText = ''; for(let [k,v] of styleItems){ cssText = cssText + k + ":" + v + ";"; } // 处理每个元素固有样式中想被保留的; for(let ele of nodeList){ let cssTmp = cssText; if(selector in this.fixedStyleObj){ let filterStyleObj = this.fixedStyleObj[selector](ele); cssTmp += filterStyleObj.cur; let oldStyle = [...this.string2DToMap(ele.style.cssText).keys()]; oldStyle.sort(); let newStyle = [...this.string2DToMap(cssTmp+filterStyleObj.delay).keys()]; newStyle.sort(); if(newStyle.toString() != oldStyle.toString()) ele.style.cssText = cssTmp; }else{ let oldStyle = [...this.string2DToMap(ele.style.cssText).keys()]; oldStyle.sort(); let newStyle = [...this.string2DToMap(cssTmp).keys()]; newStyle.sort(); if(newStyle.toString() != oldStyle.toString()) ele.style.cssText = cssTmp; } // 处理计算样式 if(Object.keys(this.variableSelector).includes(selector)){ for(let stykey of this.variableSelector[selector]){ // stykey 是每个需要计算和检查的stykey; if(styleItems.get(stykey) !== this.string2DToMap(ele.style.cssText).get(stykey)){ ele.style[stykey] = styleItems.get(stykey); } } } } } } removeStyle(selector, styleKeys=[]) { // 调试用方法 // styleKey应该是数组;eg,['width','height',...]; let currentMap = this.styleMaps.get(selector); if(!currentMap) return false; for(let key of styleKeys){ if(!currentMap.delete(key)) console.log(key+' is not exist.'); } let nodeList = document.querySelectorAll(selector); let cssText = ''; if(!currentMap.size){ this.styleMaps.delete(selector); }else{ for(let [k,v] of currentMap){ cssText = cssText + k + " :" + v + ";"; } } // 合并固有样式(始终保留,不能移除的) for(let ele of nodeList){ let cssTmp = cssText; if(selector in this.fixedStyleObj){ cssTmp += this.fixedStyleObj[selector](ele).cur; } ele.style.cssText = cssTmp; } } observeStyle() { for(let item of this.observers){ item.observer = new MutationObserver((_,obs)=>{ // 主要是根据DOM变化确定每一次变化的时候被观察元素依然存在; let flag = true; let l = 1; while(l--){ // 初始化 空,需要赋值元素 if(!item.target) { item.target = document.querySelector(item.selector); if(!item.target) { console.error('DOM变更.但是未查找到元素'); break; } this.updateGlobalStyle(); obs.observe(document.querySelector(item.eyeSlector),item.options); console.warn('DOM变更,填充空target'); } if(!item.target.isConnected){ // 说明DOM变更,前后查找到的元素不一样,但是不影响, item.target = document.querySelector(item.selector); if(!item.target) break; console.warn('DOM变更,更换旧target-修正'); // 这里还要重新监测observe obs.observe(document.querySelector(item.eyeSlector),item.options); this.updateGlobalStyle(); }else{ // 连接,但是变化太慢导致下次触发DOM变更以前为空,出现样式空白; for(let sp of item.specialJudge){ if(!item.target.style.cssText.includes(sp)){ console.warn(`DOM变更,样式空白-修正`); this.updateGlobalStyle(); break; } } } flag = false; } if(flag){ // 为真说明元素丢失;设置定时器,直到查找到并重新赋值 观察 归位 console.warn('暂时丢失,等待变更'); } }); } // 开始观察 for(let item of this.observers){ let tmpNode = document.querySelector(item.eyeSlector); if(!tmpNode){ this.updateGlobalStyle(); this.findElement(item.eyeSlector).then(rsp=>{ item.observer.observe(rsp[0],item.options); // 找到后先执行一次添加样式,因为可能eyeselector要等很久才能变更节点 this.updateGlobalStyle(); }).catch(selectorAsync=>console.error(`异步查询,未找到:${selectorAsync}`)); }else{ item.observer.observe(tmpNode,item.options); } } } subcribeGlobal(){ //开启全局事件监听--私有事件另行监听 // 1、监听URL地址变化,地址变化就更新this.styleMaps里面的背景样式; let bgImgObj = this.getSingleBg(this.getAllAvailableBg(this.configs.bg)); if(!bgImgObj){ this.setStyle(`body{background-image:none;}`); console.log('当前无有效背景图像'); return; }else{ console.log('当前背景图像: '+(bgImgObj.name||bgImgObj.url)); this.setStyle(`body{background-image:url("${bgImgObj.url}");}`); } if(this.configs.bgSwitchMode==='multi'){ history.pushState = this.wrapperEvent('pushstate',history.pushState); let changeBg = (()=>{ // 设定时间阀值,避免可能的重复设置背景 let timePrevious = new Date(); let bgImgObjPrevious = bgImgObj; return ()=>{ let timeCur = new Date(); if(timeCur-timePrevious<(this.configs.duration*1000<=1000?1000:this.configs.duration*1000)) return; let imgsAvi = this.getAllAvailableBg(this.configs.bg); if(imgsAvi.length>1){ let bgImgObjCur = this.getSingleBg(imgsAvi); for(;;){ if(bgImgObjCur === bgImgObjPrevious){ bgImgObjCur = this.getSingleBg(imgsAvi); }else{ bgImgObjPrevious = bgImgObjCur; break; } } this.setStyle(`body{background-image:url("${bgImgObjPrevious.url}");}`); console.log('当前背景图像: '+(bgImgObjPrevious.name||bgImgObjPrevious.url)); this.updateGlobalStyle(); timePrevious = timeCur; }else{ return; } }; })(); window.addEventListener('pushstate',changeBg); window.addEventListener('popstate',changeBg); } } subcribePrivate(){ //定义私有事件; } run() { this.subcribeGlobal(); this.updateGlobalStyle(); this.observeStyle(); } } /* 此类用于实例化不同网站的设置 */ class Context extends Base{ constructor(tagRules,lineRules,adRules,fixedStyleObj,observers,configs){ super(); this.startUrl = location.host; if(!(tagRules || lineRules || adRules)) throw TypeError('无效对象'); this.lineStyleSatndardRules = lineRules.standardStyle||''; this.lineStyleVariableSelector = lineRules.variableStyleSelector||''; this.tagStyleRules = tagRules||''; this.adSoft = adRules.adSoft||[]; this.adHard = adRules.adHard||[]; this.adDynamic = adRules.adDynamic||[]; this.fixedStyleObj = fixedStyleObj||{}; this.observers = observers || []; this.configs = configs || userGlobalConfigs; this.maid = []; } configInit(){ // 1、根据网速选择不同,重新包装findElement方法; let curObj = Object.getPrototypeOf(this); while(curObj){ if(Object.prototype.hasOwnProperty.call(curObj,'findElement')){ let findElement = curObj.findElement; curObj.findElement=(()=>{ let timeout,fq,intvl; switch (this.configs.netThrottlMode){ // 'low','middle','heigh','infinity' case 'low': ({timeout,fq,intvl}={timeout:7,fq:true,intvl:100}); break; case 'middle': ({timeout,fq,intvl}={timeout:12,fq:true,intvl:120}); break; case 'heigh': ({timeout,fq,intvl}={timeout:20,fq:true,intvl:300}); break; case 'infinity': ({timeout,fq,intvl}={timeout:30,fq:true,intvl:500}); break; default: ({timeout,fq,intvl}={timeout:3,fq:false,intvl:75}); } return function(selector,signal=null){ return findElement.call(this,selector,timeout,fq,intvl,signal); } })(); break; }else{ curObj = Object.getPrototypeOf(curObj); } } } globalTodo(){ //每个网站都要做的事情 // 广告软消除 document.addEventListener('load',()=>{ this.adSoft.forEach(selector=>{(new AntiAdSoft(selector.trim())).run();}) }); document.addEventListener('abort',()=>{ this.adSoft.forEach(selector=>{(new AntiAdSoft(selector.trim())).run();}) }); // 广告硬消除 for(let selector of this.adHard){ (new AntiAdHard(selector.trim())).run(); } } go(){ // 此方法用于启动所有样式广告监听等 this.configInit(); let line = new ModifyStyleFromLine(); line.configs = this.configs; line.observers = this.observers; line.fixedStyleObj = this.fixedStyleObj; line.variableSelector = this.lineStyleVariableSelector; let tag = new ModifyStyleFromTag(); // 动态广告置于此处 let adDy = new AntiAdDynamic(this.adDynamic); line.setStyle(this.lineStyleSatndardRules); //冷处理 tag.setStyle(this.tagStyleRules);//冷处理 for(let item of [line,tag,adDy]){ this.maid.push(item); item.run(); } this.globalTodo(); } } let userPrivateConfigs = Object.create(userGlobalConfigs); if(baidu&&location.href.match(/^https?:\/\/w{0,3}\.baidu\.com/i)){ // 百度私有用户配置 Object.assign(userPrivateConfigs,{ // 此处书写可以覆盖全局的配置 netThrottlMode:'low', }); // 1、Tag 配置 // #head 用于兼容谷歌浏览器渲染过慢导致的空白显示问题,firefox可以移除此项; let tagStyle = ` #s_top_wrap{ background-color: #ffffff53; backdrop-filter: blur(2px); } #s-top-more{ background-color:#ffffff4d; } #head{ background-color:rgba(255, 255, 255, 0.3)!important;box-shadow:rgba(0, 0, 0, 0.5) 2px 0px 5px 2px;backdrop-filter:blur(2px); } #s_tab>div.s_tab_inner:hover{ opacity:0.8; } #s_tab>div.s_tab_inner{ opacity:0; } #head_wrapper #kw,#form .bdsug,#form .s_ipt_wr{ background-color:#ffffffa0; } #form .s_ipt_wr,#kw{ border-top-left-radius: 1rem; border-bottom-left-radius: 1rem; } #form .bdsug li:hover{ background-color:#ffffffa0; } #foot div.foot-inner { background-color:#fff0 !important; } .wrapper_new #head.peak-down.s_down{ background-color:#fff0 !important; } #wrapper #s_tab div a,wrapper #s_tab div .s-tab-item::before,#wrapper #s_tab div b,#wrapper #s_tab div .s-tab-item::before,#wrapper #s_tab div .cur-tab::before{ color:black !important; } #wrapper #s_tab div a:hover,wrapper #s_tab div .s-tab-item::before:hover,#wrapper #s_tab div b:hover,#wrapper #s_tab div .s-tab-item::before:hover,#wrapper #s_tab div .cur-tab::before:hover{ color:blue !important; } .foot{ background-color:#ffffff4d; } #head_wrapper #s-hotsearch-wrapper,div#bottom_layer,div#s_side_wrapper{ display:none !important; } #head_wrapper.s-ps-islite{ padding-bottom:0px !important; } `; // 2、Line 配置 --- 固有样式 --- let fixedStyleObj = { "#head":function(ele){ if((new URL(ele.baseURI)).pathname=== '/'){ return {cur:'background-color:unset!important;backdrop-filter:none;',delay:''} }else{ return {cur:'',delay:''}; } }, // 侧边栏居中 "#s_tab>div.s_tab_inner":function(ele){ setTimeout(()=>{ ele.style.cssText+=`margin-top:${ele.getBoundingClientRect().height/-2}px;`; }); setTimeout(()=>{ ele.style.opacity=null; ele.style.left='0px'; },50); return {cur:'opacity:0;',delay:`margin-top:${ele.getBoundingClientRect().height/-2}px;left:0px;`}; }, "#page":function(ele){ setTimeout(()=>{ ele.style.cssText+=`margin-left:${ele.getBoundingClientRect().width/-2}px;bottom:0px;`; }); return {cur:'',delay:`margin-left:${ele.getBoundingClientRect().width/-2}px;bottom:0px;`}; } }; // 3、Line 配置 --- 标准样式 --- let lineStyle = { // #page bottom:-100px;用于解决底部栏闪烁问题;在固有样式中异步恢复 // #s_tab>div.s_tab_inner left:-100px;用于解决左侧栏闪烁问题;在固有样式中异步恢复 standardStyle:` body{ background-repeat:no-repeat;background-position:center;background-attachment:fixed;background-size:cover; } #page{ background-color:#ffffff4d;box-shadow:rgba(0, 0, 0, 0.5) 0px -1px 5px 2px;backdrop-filter:blur(2px); position:fixed;bottom:-100px;left:50%;border-radius:12px;z-index:1400; } #foot{ background-color:#ffffff00; } #page>div{ padding-left:14px; } #container{ background-image:linear-gradient(to right,rgba(255, 255, 255, 0.75) 25%,rgba(255, 255, 255, 0.15));box-sizing:border-box; box-shadow:rgba(0, 0, 0, 0.5) 0px 0px 5px 2px,inset 0px 0px 5px 1px white;margin-bottom:0.5rem;padding:2.5em;border-radius:12px; } #head{ background-color:rgba(255, 255, 255, 0.3)!important;box-shadow:rgba(0, 0, 0, 0.5) 2px 0px 5px 2px;backdrop-filter:blur(2px); } #s_tab>div.s_tab_inner{ position:fixed;left:-100px;z-index:302;top:50%;border-top-right-radius:16px;border-bottom-right-radius:16px;width:60px; transition:all 0.3s;background-color:#fff; } `, // Line 配置 --- 计算样式(选择) --- variableStyleSelector:{ 'body':['background-image'], } } // 4、Ad 配置 let adRules = { // 4、Ad (soft)配置 adSoft:[ '.s-hotsearch-wrapper.s-isindex-wrap','.s-isindex-wrap.s-bottom-layer','[tpl=recommend_list]', '#rs_new','#s_side_wrapper','#content_right div.hint_right_middle','#help','#searchTag', ], // 4.1 Ad (hard配置) adHard:[], adDynamic:[], } // 5、监测配置(Line) let obs4DOM = [ {'selector':'#head',"target":null,'eyeSlector':'body','observer':null,'options':{childList:true},specialJudge:['background-color']}, //{'selector':'#s_tab>div.s_tab_inner',"target":null,'eyeSlector':'#s_tab','observer':null,'options':{childList:true},specialJudge:['opacity']}, //{'selector':'#wrapper',"target":null,'eyeSlector':'body','observer':null,'options':{childList:true},specialJudge:[]}, {'selector':'#page',"target":null,'eyeSlector':'#wrapper_wrapper','observer':null,'options':{childList:true,subtree:true},specialJudge:[]}, ]; // 启动 window.$_SM = new Context(tagStyle,lineStyle,adRules,fixedStyleObj,obs4DOM,userPrivateConfigs); window.$_SM.go(); }else if(sou360&&location.href.match(/^https?:\/\/w{0,3}\.so\.com/i) && location.pathname.toLowerCase() === '/'){ //360首页 Object.assign(userPrivateConfigs,{ // 此处书写可以覆盖全局的配置 netThrottlMode:'low', }); // 1、Tag 配置 let tagStyle = ` #footer{ display:none; } #header{ background-color:#ffffff6b; backdrop-filter:blur(2px); } fieldset#input-container{ background-color:rgba(255, 255, 255, 0.75); } div#suggest-align{ background-color:#ffffff00; } div#goto-top{ display:none!important; } `; // 2、Line 配置 --- 固有样式 --- let fixedStyleObj = { //selector:function(ele){} }; // 3、Line 配置 --- 标准样式 --- let lineStyle = { standardStyle:` body{ background-repeat:no-repeat;background-position:center;background-attachment:fixed;background-size:cover; } #skin_bg{ background-color:rgba(255, 255, 255, 0); } #card_container{ display:none; } #bd_search .fixed{ background-color:rgba(255, 255, 255, 0); } `, // Line 配置 --- 计算样式(选择) --- variableStyleSelector:{ '#skin_bg':['background-color'], // 都要有的背景 'body':['background-image'], } } // 4、Ad 配置 let adRules = { // Ad (soft)配置 adSoft:[], // Ad 硬处理(只能删除节点的类型);给选择器即可 adHard:[ '#goto-top','#often_so' ], // Ad 专用动态规则集 adDynamic:[ //{ref:'#lawnfooter-samll__btne',fire:(eles)=>{return [eles[0]]},options:{childList:true}}, {ref:'#lawnfooter-samll__btn',eyeSlector:'body',options:{childList:true},fire:(eles)=>{ //eles 是重找规则里面的元素集 let pE = eles[0]; for(;;){ if (pE.parentElement === document.body){ return [pE]; }else{ pE = pE.parentElement; } } },}, ], } // 5、监测配置(Line) let obs4DOM = [ {'selector':'#card_container',"target":null,'eyeSlector':'#main','observer':null,'options':{childList:true},specialJudge:['display']}, ]; window.$_SM = new Context(tagStyle,lineStyle,adRules,fixedStyleObj,obs4DOM,userPrivateConfigs); window.$_SM.go(); }else if(sou360&&location.href.match(/^https?:\/\/w{0,3}\.so\.com/i) && location.pathname.toLowerCase() === '/s'){ //360搜索结果页面 Object.assign(userPrivateConfigs,{ // 此处书写可以覆盖全局的配置 netThrottlMode:'low', }); // 1、Tag 配置 let tagStyle = ` html{ background-color: unset !important; } div#header{ background-color: transparent; } #header div.inner{ background: #ffffff70; box-shadow: black 0px 0px 5px 1px; backdrop-filter: blur(2px); } ul.g-menu{ background-color: #ffffffe8; } #g-hd #head .round{ background-color: #ffffffb0; } #head #keyword{ background-color: #fff0; } div#tabs-wrap{ border:none; } ul#g-hd-tabs{ position: fixed; width: min-content; left: 0px; top:50%; height:min-content; transform:translateY(-50%); background-color: #eee; z-index:3000; border-top-right-radius:16px; border-bottom-right-radius:16px; opacity:0; transition:opacity 0.3s; } ul#g-hd-tabs:hover{ opacity:0.85; } ul#g-hd-tabs li a{ color:black; } div#container{ margin: 0px 8% auto; padding: 1.2rem; border-radius: 12px; background-image: linear-gradient(to right,rgba(255, 255, 255, 0.75) 25%,rgba(255, 255, 255, 0.15)); box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px 2px,inset 0px 0px 5px 1px white; border-radius: 12px; margin-bottom: 6rem; } div#main{ padding-left: 1.2rem; width:55%; margin-right:8%; } #warper div.mod-relation,#main .inline-recommend{ display: none !important; } #warper #page{ position: fixed; bottom: 0px; margin: 0px; left:0px; right:0px; z-index: 3000; padding-left: 10px; background-color: #ffffff4d; box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 5px 2px; backdrop-filter: blur(2px); border-radius: 10px; padding-top: 14px; padding-bottom: 14px; margin-left: auto; margin-right: auto; width: min-content; } #page span.nums{ display: none !important; } div#page a, div#page strong{ background: #fff; border: 1px solid #eee; border-radius: 8px; color: #666; display: inline-block; font-size: 14px; height: 34px; line-height: 34px; margin-right: 12px; text-align: center; text-decoration: none; vertical-align: middle; width: 34px; } div#page strong{ background: #0fb264; border-color: #0fb264; box-shadow: 0 1px 3px rgba(188,188,188,0.2); color: #ffffff; } div#footer{ display:none; } #warper #side{ left:0px; } #mohe-hotnews_right .mh-small-box,#side #adwarnTip,#side #so_kw-ad,#side #lm-rightbottom,div.lianmeng-ad,dl#head_rs_top,#rs-top,.kzx-news-rec-info, .lianmeng-ad,#side div.res-mediav-right,dl#head_pdr_guide,div#so_top,div.res-recommend-tag,.double-eleven,div#goto-top{ display:none!important; } #warper #side:hover{ background-color:unset!important; } div#side_wrap.fixed{ background-color:rgba(255, 255, 255, 0)!important; } `; // 2、Line 配置 --- 固有样式 --- let fixedStyleObj = { // 左侧面板居中 // 底部栏 }; // 3、Line 配置 --- 标准样式 --- let lineStyle = { standardStyle:` body{ background-repeat:no-repeat;background-position:center;background-attachment:fixed;background-size:cover; } `, // Line 配置 --- 计算样式(选择) --- variableStyleSelector:{ // 都要有的背景 'body':['background-image'], } } // 4、Ad 配置 let adRules = { // Ad (soft)配置 adSoft:[], // Ad 硬处理 adHard:[ '#so_kw-ad' ], // Ad 专用动态规则集 adDynamic:[ {ref:'#so_top',eyeSlector:'body',options:{childList:true,subtree:true},fire:(eles)=>{return [...eles]}}, {ref:'#head_pdr_guide',eyeSlector:'#tabs-wrap',options:{childList:true,subtree:true},fire:(eles)=>{return [...eles]}}, ], } // 5、监测配置(Line) let obs4DOM = [ {'selector':'body',"target":null,'eyeSlector':'body','observer':null,'options':{attributeFilter:['style']},specialJudge:['backgound-image']}, ]; window.$_SM = new Context(tagStyle,lineStyle,adRules,fixedStyleObj,obs4DOM,userPrivateConfigs); window.$_SM.go(); } console.log('running'); })()